/* BSD Socket API Example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include <sys/param.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_netif.h"

#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include <lwip/netdb.h>



int sock;



#define PORT                        (3333)
#define KEEPALIVE_IDLE              (7200)  //空闲7200秒开始
#define KEEPALIVE_INTERVAL          (72)
#define KEEPALIVE_COUNT             (5)

static const char *TAG = "[my tcp_server]";

// 61 64 61 70 74 65 72  ==》 adapter 的ascii码
//identifier 固定7字节  ==》  uint8_t identifier[7];



struct identifier
{
    uint8_t byte_list[7];
    uint8_t len;
};

struct adapter_msg_tx{
    struct identifier msg_id;
    uint8_t header_size;
    uint8_t* header;
    uint8_t body_size;
    uint8_t* body;
};

struct adapter_msg_tx DEFAULT_CONFIG_MSG = {
    .msg_id = {
        .byte_list = {0x61, 0x64, 0x61, 0x70, 0x74, 0x65, 0x72},  // "adapter" 去掉'\0'
        .len = 7 
        },
    .header_size = 0,
    .header = NULL,
    .body_size = 0,
    .body = NULL,

};

struct adapter_msg_rx{
    uint8_t header_size;
    uint8_t* header;
    uint8_t body_size;
    uint8_t* body;
    //
    bool is_new;
};


void send_heart_beat()
{
/**
 * identifier：61 64 61 70 74 65 72  ==> adapter 的ascii码
 * header_size: 0x2
 * header: 48 42 ==> HB 【意思是 heard-beat】
 * body_size: 0x0
 * body: 【无】
 */
    uint8_t buf[128];

    struct adapter_msg_tx heart_beat_msg = DEFAULT_CONFIG_MSG;
    heart_beat_msg.header_size = 2;
    heart_beat_msg.header = "HB";
    "\x12\x13"




    uint8_t* pos = buf;
    memcpy(pos, msg_id.byte_list, msg_id.len);
    pos += msg_id.len;
    //
    uint8_t header_size = 2;
    memcpy(pos, &header_size, 1);
    pos += 1; 
    //
    memcpy(pos, "HB", strlen("HB"));
    pos += strlen("HB");
    //
    uint8_t body_size = 0;
    memcpy(pos, &body_size, 1);
    pos += 1; 
    //完成 tcp流 填充；
    


}



void tcp_server_wait_connect(void)
{
    char addr_str[128];
    int addr_family = AF_INET;
    int ip_protocol = 0;
    int keepAlive = 1;
    int keepIdle = KEEPALIVE_IDLE;
    int keepInterval = KEEPALIVE_INTERVAL;
    int keepCount = KEEPALIVE_COUNT;
    struct sockaddr_storage dest_addr;


    if (addr_family == AF_INET) {
        struct sockaddr_in *dest_addr_ip4 = (struct sockaddr_in *)&dest_addr;
        dest_addr_ip4->sin_addr.s_addr = htonl(INADDR_ANY);
        dest_addr_ip4->sin_family = AF_INET;
        dest_addr_ip4->sin_port = htons(PORT);
        ip_protocol = IPPROTO_IP;
    }


    int listen_sock = socket(addr_family, SOCK_STREAM, ip_protocol);
    if (listen_sock < 0) {
        ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
        return;
    }
    int opt = 1;
    setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    ESP_LOGI(TAG, "Socket created");

    int err = bind(listen_sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
    if (err != 0) {
        ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno);
        ESP_LOGE(TAG, "IPPROTO: %d", addr_family);
        return;
    }
    ESP_LOGI(TAG, "Socket bound, port %d", PORT);

    err = listen(listen_sock, 1);
    if (err != 0) {
        ESP_LOGE(TAG, "Error occurred during listen: errno %d", errno);
        return;
    }

    while (1) {
        ESP_LOGI(TAG, "Socket listening");

        struct sockaddr_storage source_addr; // Large enough for both IPv4 or IPv6
        socklen_t addr_len = sizeof(source_addr);
        sock = accept(listen_sock, (struct sockaddr *)&source_addr, &addr_len);
        if (sock < 0) {
            ESP_LOGE(TAG, "Unable to accept connection: errno %d", errno);
            break;
        }

        // Set tcp keepalive option
        setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &keepAlive, sizeof(int));
        setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &keepIdle, sizeof(int));
        setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &keepInterval, sizeof(int));
        setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &keepCount, sizeof(int));
        // Convert ip address to string

        if (source_addr.ss_family == PF_INET) {
            inet_ntoa_r(((struct sockaddr_in *)&source_addr)->sin_addr, addr_str, sizeof(addr_str) - 1);
        }

        ESP_LOGI(TAG, "Socket accepted ip address: %s", addr_str);
        while (1)
        {
            vTaskDelay(pdMS_TO_TICKS(5000));
        }
        
    }

}
